﻿using System;
using System.IO;
using System.Net;
using System.Text;
using AgFx;

namespace USElections.Utils
{
    public class MyWebLoadRequest : LoadRequest
    {
        public MyWebLoadRequest(LoadContext loadContext, Uri uri)
            : base(loadContext)
        {
            this.Uri = uri;
            this.Method = "GET";
        }

        public MyWebLoadRequest(LoadContext loadContext, Uri uri, string method, string data)
            : this(loadContext, uri)
        {
            this.Method = method;
            this.Data = data;
        }

        public string ContentType { get; set; }
        public string Data { get; private set; }
        public string Method { get; private set; }
        public Uri Uri { get; private set; }

        protected virtual HttpWebRequest CreateWebRequest()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Uri);
            request.Method = this.Method;

            if (!string.IsNullOrEmpty(this.ContentType))
            {
                request.ContentType = this.ContentType;
            }

            return request;
        }

        public override void Execute(Action<LoadRequestResult> result)
        {
            if (result == null)
            {
                throw new ArgumentNullException();
            }

            PriorityQueue.AddNetworkWorkItem(delegate
            {
                AsyncCallback callback = null;
                HttpWebRequest request = this.CreateWebRequest();

                AsyncCallback responseHandler = delegate(IAsyncResult asyncObject)
                {
                    HttpWebResponse response = null;
                    
                    try
                    {
                        response = (HttpWebResponse)request.EndGetResponse(asyncObject);
                    }
                    catch (WebException exception)
                    {
                        result(new LoadRequestResult(exception));
                        return;
                    }
                    if (!this.IsGoodResponse(response))
                    {
                        result(new LoadRequestResult(new WebException("Bad web response, StatusCode=" + response.StatusCode)));
                    }
                    else
                    {
                        byte[] buffer = new byte[response.ContentLength];
                        Stream responseStream = response.GetResponseStream();
                        responseStream.Read(buffer, 0, buffer.Length);
                        responseStream.Close();
                        result(new LoadRequestResult(new MemoryStream(buffer)));
                    }
                };
                if (this.Data != null)
                {
                    request.AllowReadStreamBuffering = true;
                    try
                    {
                        if (callback == null)
                        {
                            callback = delegate(IAsyncResult asyncObject)
                            {
                                Stream stream = request.EndGetRequestStream(asyncObject);
                                byte[] bytes = Encoding.UTF8.GetBytes(this.Data);
                                stream.Write(bytes, 0, bytes.Length);
                                stream.Close();
                                request.BeginGetResponse(responseHandler, null);
                            };
                        }
                        request.BeginGetRequestStream(callback, null);
                    }
                    catch (SystemException exception)
                    {
                        result(new LoadRequestResult(exception));
                    }
                }
                else
                {
                    request.BeginGetResponse(responseHandler, null);
                }
            });
        }

        protected virtual bool IsGoodResponse(HttpWebResponse response)
        {
            return (response.StatusCode == HttpStatusCode.OK);
        }
    }
}
